package cn.taobaoke.restful.util;

import okhttp3.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * OkHttpUtil类.
 * +-----------------------------------------------------------------------------------------------+
 * |类名称: OkHttpUtil                                                                         |
 * |创建时间: 4/23/17                                                                               |
 * |功能简介:                                                                                       |
 * |参考链接:                                                                                       |
 * +-----------------------------------------------------------------------------------------------+
 *
 * @author luch
 */
public class OkHttpUtil {
    static Logger logger = LogManager.getLogger(OkHttpUtil.class);

    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType TEXT = MediaType.parse("application/text; charset=utf-8");

    public static OkHttpUtil DEFAULT = new OkHttpUtil(10, 10, 10000);

    private OkHttpClient client;

    public OkHttpUtil() {
        client = new OkHttpClient.Builder()
                .connectTimeout(10000L, TimeUnit.MILLISECONDS)
                .readTimeout(10000L, TimeUnit.MILLISECONDS).build();
    }

    /**
     * 设置HttpRequset
     *
     * @param maxConnection     连接池中,最大连接数
     * @param keepAliveDuration 连接池池,链接空闲保持时间
     * @param timeout           超时时间
     */
    public OkHttpUtil(int maxConnection, int keepAliveDuration, int timeout) {
        client = new OkHttpClient.Builder()
                .connectionPool(new ConnectionPool(maxConnection, keepAliveDuration, TimeUnit.MINUTES))
                .connectTimeout(timeout, TimeUnit.MILLISECONDS)
                .readTimeout(timeout, TimeUnit.MILLISECONDS).build();
    }


    public String get(String url) throws IOException {
        Request request = new Request.Builder().url(url).build();
        return execute(request);
    }

    public String post(String url, Map<String, String> params) throws IOException {
        FormBody.Builder builder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            builder.add(entry.getKey(), entry.getValue());
        }
        FormBody formBody = builder.build();
        return post(url, formBody);
    }

    /**
     * Post表单请求
     *
     * @param url      请求地址
     * @param formBody 表单参数。 补: 与 Map<String, String> 区别在于支持传递数组, array[] -> value 方式。
     * @return string
     * @throws IOException 遇到链接错误或超时返回该异常
     */
    public String post(String url, FormBody formBody) throws IOException {
        Request request = new Request.Builder().url(url).post(formBody).build();

        return execute(request);
    }

    public String postText(String url, String body) throws IOException {
        return postWithContentType(url, TEXT, body);
    }


    public String postJson(String url, String json) throws IOException {
        return postWithContentType(url, JSON, json);
    }


    public String postWithContentType(String url, MediaType type, String body) throws IOException {
        RequestBody requestBody = RequestBody.create(type, body);
        Request request = new Request.Builder().url(url).post(requestBody).build();

        return execute(request);
    }

    private String execute(Request request) throws IOException {
        logger.info("{} {}", request.method(), request.url().toString());
        long start = System.currentTimeMillis();

        try (Response response = client.newCall(request).execute()) {
            String ret = response.body().string();
            long end = System.currentTimeMillis();

            logger.info("request: {}, response: {} ", request.url(), ret);
            logger.info("{} {} (done {} ms)", request.method(), request.url().toString(), (end - start));
            return ret;
        }
    }
}
